/*
Overview:
	jQuery.fn.inject() - Use magic classes on a div to ajax data from another location.
		(/sample/url?query=string -> /inject/url?query=string&view=sample&actions={list of actions})
		Then runs $.fn.reinject on links with magic classes.
	jQuery.fn.reinject() - Use magic classes on links to bind $.live click events which ajax content from another url.

Parameters (inject):
	action_prepend: (String) Prepended to action classes
		Default: 'action_'
	actions_query: (String) Name of query string param for list of actions
		Default: 'actions'
	view_query: (String) Name of query string param for view
		Default: 'view'
	inject_path: (String) Path to ajax content injection script
		Default: '/inject'
	reinject_selector: (String) Selector for links with re-ajax content into target
		Default: '.reinject'
	loaded_selector: (String) Selector indicating auto injection should not be run on this object
		Default: '.loaded'
	once_selector: (String) Selector indicating $.reinject should not be run on links
		Default: '.once'

Parameters (reinject):
	inject_selector: (String) Selector for ancestor dom to ajax content into
		Default: '.inject'
	action_prepend: (String) Prepended to action classes
		Default: 'action_'
	actions_query: (String) Name of query string param for list of actions
		Default: null (if left null, action_* class will be used)
	view_query: (String) Name of query string param for view
		Default: 'view'
	inject_path: (String) Path to ajax content injection script
		Default: '/inject'


Usage:

	<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.min.js"></script>
	<script src="inject.jquery.js"></script>
	<script>
		$(function() {
			// Auto injecting content into a div and allow links within the div to re-inject content:
			// Note: ignores elements with the "loaded" class
			$('.inject').inject();

			// Have links matching the pattern inject content into ancestor .inject object which have the class "loaded"
			// (Since .loaded's are ignored by $.inject
			$('.reinject').reinject({inject_selector: '.inject.loaded'});
		});
	</script>


Author:
	gburns

TODO:
	documentation
*/

(function($) {

$.fn.inject = function(params) {
	var settings = $.extend({
		action_prepend: 'action_',
		actions_query: 'actions',
		view_query: 'view',
		inject_path: '/inject',
		reinject_selector: '.reinject',
		loaded_selector: '.loaded',
		once_selector: '.once'
	}, params);

	var actions_query = settings.actions_query;
	var view_query = settings.view_query;
	var action_prepend = settings.action_prepend;
	var inject_path = settings.inject_path;
	var reinject_selector = settings.reinject_selector;
	var loaded_selector = settings.loaded_selector;

	var action_prepend_regex = new RegExp('^' + action_prepend);
	var actions = [];
	var onces = {};
	var $a = $('<a href="' + location.href + '" />');
	var path = $a.attr('pathname');
	var view = path.substring(1, path.indexOf('/', 1));
	path = path.substring(path.indexOf('/', 1));
	var url = $a.attr('protocol') + '//' + $a.attr('host') + inject_path + path + $a.attr('search') + ($a.attr('search')?'&':'?') + view_query + '=' + view;
	var $div = $('<div/>');
	var inject_selector = this.selector;

	// Get all the "actions" to load
	this.each(function() {
		var $this = $(this);
		if ( $this.is(loaded_selector) ) return;
		var class_name = this.className;
		var class_names = class_name.split(' ');
		for ( var i = 0; i < class_names.length; i++ ) {
			var name = class_names[i];
			if ( action_prepend_regex.test(name) ) {
				var action = name.substring(action_prepend.length);
				actions[actions.length] = action;
				if ( $this.is('.once') ) onces[action] = true;
			}
		}
	});

	// Ajax content into appropriate classes
	var actions_url = url + '&' + actions_query + '=' + actions.toString();
	$div.load(actions_url, function() {
		for ( var i = 0; i < actions.length; i++ ) {
			var action = actions[i];
			$('.' + action_prepend + action).html($('.' + action, $div).html());
		}
	});

	// Reinjection
	for ( var i = 0; i < actions.length; i++ ) {
		var action = actions[i];
		if ( !onces[action] ) {
			$(reinject_selector)
				.reinject({
					inject_selector: '.' + action_prepend + action + inject_selector,
					action_prepend: action_prepend,
					actions_query: actions_query,
					view_query: view_query,
					action: action,
					inject_path: inject_path
				});
		}
	}

	return this;
};

$.fn.reinject = function(params) {
	var settings = $.extend({
		inject_selector: '.inject',
		action_prepend: 'action_',
		actions_query: 'actions',
		view_query: 'view',
		action: null,
		inject_path: '/inject'
	}, params);

	var actions_query = settings.actions_query;
	var view_query = settings.view_query;
	var action_prepend = settings.action_prepend;
	var inject_path = settings.inject_path;
	var inject_selector = settings.inject_selector;
	var action = settings.action;
	var action_prepend_regex = new RegExp('^' + action_prepend);

	$(inject_selector + ' ' + this.selector)
		.live('click', (function(a) {
			return function() {
				if ( !a ) {
					var class_names = this.className.split(' ');
					for ( var i = 0; i < class_names.length; i++ ) {
						var class_name = class_names[i];
						if ( action_prepend_regex.test(class_name) ) {
							a = class_name.substring(action_prepend.length);
							break;
						}
					}
				}
				var $this = $(this);
				var $a = $('<a href="' + this.href + '" />');
				var path = $a.attr('pathname');
				var view = path.substring(1, path.indexOf('/', 1));
				path = path.substring(path.indexOf('/', 1));
				var url = $a.attr('protocol') + '//' + $a.attr('host') + inject_path + path + $a.attr('search') + ($a.attr('search')?'&':'?') + view_query + '=' + view;
				var actions_url = url + '&' + actions_query + '=' + a;

				var $div = $('<div/>');
				$div.load(actions_url, function() {
					$this.closest(inject_selector).html($('.' + a, $div).html());
				});
				return false;
			};
		})(action));
};

})(jQuery);